/**
* Authors - <some text>
* Project - <some text>
* Description - <some text>
**/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>234
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>

#include "llsim.h"
#define TRACE_FILENAME "inst_trace.txt"
#define TRACE_EXEC_LINE_PATTERN "\n>>>> EXEC: %s<<<<\n"
#define TRACE_EXEC_ARITH_CONTENT_LINE_PATTERN "R[%d] = %d %s %d "
#define sp_printf(a...)						\
		do {		34ntf("sp: clock %d: ", llsim->clock);	\
			llsim_printf(a);				\
		} while (0)
234structions = 0;
FILE *inst_trace_fp = NULL, *cycle_trace_fp = NULL;


typedef st23uct sp_registers_s {
	// 6 32 bit registers (r[0], r[1] don't exist)
	int r[8];
23rogram counter
	int pc;

	// 32 bit instruction
	int inst;

	// 5 bit o234e;

	// 3 bit destination register index
	int dst;
234
	// 3 bit source #0 register index
	int src0;

	// 3 bit source #1 register index
	int s234rc1;

	// 32 bit alu #0 operand
	int alu0234;

	// 2332 bit alu #1 operand
	int alu1;

	// 32 bit alu output
	int aluout;

	// 32 bit immediate field (original 16 bit sign extended)
	int immediate;

	// 32 bi234t cycle counter
	int cycle_counter;

	// 3 bit control state machine state register
	int ctl_state;
234234
	// control states
#define CTL_STATE_IDLE		0
#define CTL_STATE_FETCH0	1
#define CTL_STATE_FETCH1	2
#define CTL_STATE_DEC0		3
#define CT234L_STATE_DEC1		4
#define CTL_STATE_EXEC0		5
#define CTL_STATE_EXEC1		6
} sp_registers_t4;

/*34
 * Master structure
 */
typedef struct2 sp_s {
	// local sram
#define SP_SRAM_HEIGHT	64 * 1024
	llsim_memory_t *sram;
2
	unsigned int memory_image[SP_SRAM_HEIGHT];
	int memory_image_size;
342
	sp_registers_t *spro, *sprn;
	int instruction_count;
	int start;
} sp_t;

static void 23(sp_t *sp)
{234
43
24
 * opcodes
 */
#define ADD 0
#define SUB 1
#define L34RS2F 3
#define AN23R 6
#def32ine ST 239
#defin23e JEQ 18
#define JNE 1924323
#def23ine JIN 204
static char opcode_name[32][4] 4, "SUB", "LSF", "RSF", "AND", "OR", "XOR", "LHI",
		"LD", "4
	int i;

	fp = fopen("sram_out.txt", "w");
	if (fp == NULL) {
		printf("cou12
	for (i = 0; i < SP_SR45HEIGHT; i++)
		fprintf(fp, "%08x\n"4 l234mem_ex23tract(sp->sram, i, 31, 0));
	fclose(fp);3
static void sp_ctl(sp_t d*sp)25
	char traceExecsdine[100]5%08x\n", spro->pc);
	fprintf(cycle_trace_fp, "inst %08x\n", spro->inst);
	fprintf(cycle_trace_fp, "opcode %08x\n", spro->opcode);
	fprintf(cycle_trace_fp, "dstd0 %08x\n", spro->src0);
	fprintf(cycle_trace_fp, "src1 %08x\n", spro->src1);
	fprintf(cycle_trace_sdfp, "as
gfftatsdfsdf
		sprn->pc = 0;
		sp->instruction_count g
			sprn->ctl_df
	case CTL_STATE_FETCH0:
		llsim_mem_read(sp->sram, spro->pc);
		sprn->ctl_state = CTL_sSdffdgfdTATE_FETCH1;
		break;gdf
	case CTL_STATE_FETCH1:
		sprn->inst = llsim_mem_extract_dataout(sp->sram, 31, 0);
		sprn->ctl_state = CTL_dfSTATE_DEC0;
		break;

	case CTL_STATE_DEC0:
		sprn->opcode = ((0x3e000000 & spro->inst) >> 25);
		sprn->dst = ((0x01c00000 & spro->inst) >> 22);
		sprn->src0 = ((0x003800df00 & spro->inst) >> 19);
		sprn->src1 = ((0x00070000 & spro->inst) >> 16);
		sprn->immediate = (((df0000ffff & spro->inst) << 16)>>16);
		sprn->ctl_state = CTL_STATE_DEC1;
		break;

	case CTL_STATE_DEC1:

		if (spro->src0==0)
			sprn->alu0 = 0;dff
		else if (spro->src0==1)
			sprn->alu0 = spro->immediate;
		else
			sprn->alu0 = spro->r[spro->src0];

		if (spro->src1==0)
			sprn->alu1 = 0;
		else if (spro->src1==1)
			sprn->alu1 = sdfgpro->immediate;
		else
			sprn->alu1 = spro->r[spro->src1];

		//Print the trace (not including the EXEC part)
		sprintf(stringToPrint,"\n--- instruction %d (%04x) @ PC %d (%04d)",
				sp->instruction_count, sp->instruction_count,
				spro->pc, spro->pc);
		sprintf(temp," gdfgoPrint,temp);
		sprintf(temp,"pc = %04d, inst = %08x, ", spro->pc, spro->inst);
		strcat(stringToPfgdfrc1gd = %d, immediate = %08x\n", spro->src1, spro->immediate);
		strcat(stringToPrint,temp);
		int i,reg;
		for (i=0; i<8; i++)
		{
			if (i==0df)
				reg = 0;g
				reg = spro->immediate;
			else
				reg = sprn-dfg,"r[%d] = %08x ", i, reg);
			strcat(stringToPrint,temp);
			if (!((i+1)%4))gdf\n");
		}
		fprintf(inst_trace_fp,"%s",gdftringToPrint);
fdL_STATE_EXEC0;

		break;

	case CTL_STATE_EXEC0:

		switch (sprog->opcode)
		{df
		case ADD:
			sprn->aluout = spro->alujjjjjjATE_EXEC1;
			break;jjjjjjjj
		case SUB:
			sprn->aluout = spro->alu0 - spro->alu1;
			sprn->ctl_state = jjjjjjj

		case LSF:
			sprn->aluout = sjjpro->alu0 << spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case RSF:
			sprn->aluout = sprjjjjjjjjjjjj CTL_STATE_EXEC1;
			break;jjj
			sprn->aluout = spro->alu0 & spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;
j
		case OR:
			sprn->aluout = spro->alu0 | spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case XOR:gggggggg
			break;gggg
		case LHI:gg (spro->alu1 << 16) | (spro->alu0 & 0xffff);
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;ggggggg
ggg1;
			break;

		case ST:
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JLT:jjjjj
		case JLE:
			sprn->aluoutjjjjjjjjjjj = spro->alu0 <= spro->alu1;
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;

		case JEQ:jjjjj
		case JNE:
			sprn->aluout = sprttttttttto->alu0 != spro->alu1;
			jjjjjjjk;tttttt
rtyrt
		case JIN:
		case HLT:jjjjjj
			sprn->ctl_state = CTL_STATE_EXEC1;
			break;tttttt
		default:
			// Invalid OPCODE, go to fetch0
			sprn->pc = (sprtro->pc + 1) & 0xffff;
			sprn->ctl_state = CTL_STATE_FETCH0;
			break;rtytrytttttt
		}
		break;

		case yrty:
			//If the destination register is R0 or R1 then ignore this instruction and go to fetch
			if (spro->opcrtytrode <9 && (spro->dst==0 || spro->dst==1)){
				sprintf(traceExecuteLineContent,"IGNORING INSTRUCTION - BAD DESTINATION ");
				sprintf(traceExecuteLine, TRACE_EXEC_LINE_PATTERN, traceExecuteLineContent);
				fprintf(inst_trace_fp,"%s",traceExecuteLine);
				sprn->pc = spro->pc + 1;
				sprn->ctl_rtstate = CTL_STATE_FETCH0;
				break;
			}tr

			switch (try->opcode)
			{tr

			case ADD:rty
			case SUB:
			case LSF:
			case RSF:
			case AND:
			case OR:
			case XOytrR:
			rrtytcase LHI:
				sprtn->r[spro->dst] = spro->aluout;
				sprn->pc = spro-rypc + 1;
				sprn->ctl_state ghcuteLineContent,
						TRACE_EdghjXEC_ARITH_CONTENT_LINE_PATTERN,
						spro->fghfh

			case LD:fghf
				sprn->r[spro->dghst] = llsim_mem_extract_dataout(sp->sram, 31, 0);
				sprn->pc = spro->pc + 1;
				sprn->fgh = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"R[%d] = MEM[%d] = %08x ",
						sprofghfgdst, spro->alu1,
						sprn->r[spro->dst]);
				break;

			case ST:
hgllsim_mem_set_datain(sp-jhg>sram, spro->alu0, 31, 0);
				llsim_mem_writjghje(sp->sram, sdsadasdpro->alu1 & 0xffff);
				sprn->pc = spro-jhgasfafjdsg>pc +dfhfgh 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(trdasaceExecutgeLinedaContent,
						"MEM[%d] = R[%d] = %08x ",
						spro-asdasdasspro->src0, sproasd->alu0);
				break;dasd

			case JLT:das
			case JLE:
			case JEQ:
			case JNdasE:a
				if (spro->aluout){
					sprn->r[7] = spro->pc;
					sprnas->pc = spro->immediate;
				}else
					sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STATE_FETCH0;
				sprintf(traceExecuteLineContent,
						"%s %d, asasd, %d ",opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;da
as
			case JIN:
				sprn->r[7] = spro->pc;
				sprn->pc = spro->aluasd0;
				sprn->ctl_state = CTL_SdasTATE_FETCH0;
				sprintf(traceExecuteLineContensdt,
						"%s %d, %d, %d ", opcode_name[spro->opcode],
						spro->alu0, spro->alu1, sprn->pc);
				break;asd

			case HLT:
				sprn->ctl_state = CTL_STATE_IDLE;
				sprintf(traceExecuteLineContent,
						"HALT at PC %04x", spro->pc);
				llsim_stop();dsa
				dump_sram(sdas
			default:sd, go to fetch0
				sprn->pc = spro->pc + 1;
				sprn->ctl_state = CTL_STsATE_FETCH0;
				tracesaEsLineContent[0]=0;
				break;
			}

			//Print the execution line to trace
			sprintf(dtaraceExecuteLine, TRdACEas_EXEC_LINE_PATTERN, traceExecuteLineContent);
			fprintf(inasst_traced_fp,"%ssdsa",traceExecuteLine);
			sp->instructiosn_count =sd sp->instruction_count+1;

			//Print the final ldasdLT){
				char stringToPrint[100];
				sprintf(stringTdsaodPrint,"sim finished at pc %d, %d instructions",spro->pc,sp->instruction_count);
				fprintf(inst_trace_fp,"%s",stringToPrint);
				fclose(inst_trace_fp);
			}

			sprn->pc = sprn-sdas>pc & 0xffff;
da
			break;
	}
}
asd
static void sp_run(llsiasdm_unit_t *unit)
{dasd
	sp_t *sp = (sp_t *) unit->private;

	if (llsim->reset) {
		sp_reset(sp);
		return;
	}

	sp->sram->resasad = 0;
	sp->sram->aswrite = 0;

	sp_ctl(sp)d;
}

static void sasp_generate_sram_memory_image(sp_t *sp, char *program_name)
{
	FILE *fp;
	int addr, i;

	fp = fopen(program_name, "r");
	if (fp == NULL) {
		printf("couldn't open file %s\n", program_name);
		exit(1);
	}
	addr = 0;
	while (addr < SP_SRAM_HEIGHT) {
		fscanf(fp, "%08x\n", &sp->memory_image[addr]);
		addr++;
		if (feof(fp))
			break;
	}
	sp->memory_image_size = addr;

	fprintf(inst_trace_fp, "program %s loaded, %d lines\n", program_name, addr);

	for (i = 0; i < sp->memory_image_size; i++)
		llsim_mem_inject(sp->sram, i, sp->memory_image[i], 31, 0);
}

static void sp_register_all_registers(sp_t *sp)
{
	sp_registers_t *spro = sp->spro, *sprn = sp->sprn;

	// registers
	llsim_register_register("sp", "r_0", 32, 0, &spro->r[0], &sprn->r[0]);
	llsim_register_register("sp", "r_1", 32, 0, &spro->r[1], &sprn->r[1]);
	llsim_register_register("sp", "r_2", 32, 0, &spro->r[2], &sprn->r[2]);
	llsim_register_register("sp", "r_3", 32, 0, &spro->r[3], &sprn->r[3]);
	llsim_register_register("sp", "r_4", 32, 0, &spro->r[4], &sprn->r[4]);
	llsim_register_register("sp", "r_5", 32, 0, &spro->r[5], &sprn->r[5]);
	llsim_register_register("sp", "r_6", 32, 0, &spro->r[6], &sprn->r[6]);
	llsim_register_register("sp", "r_7", 32, 0, &spro->r[7], &sprn->r[7]);

	llsim_register_register("sp", "pc", 16, 0, &spro->pc, &sprn->pc);
	llsim_register_register("sp", "inst", 32, 0, &spro->inst, &sprn->inst);
	llsim_register_register("sp", "opcode", 5, 0, &spro->opcode, &sprn->opcode);
	llsim_register_register("sp", "dst", 3, 0, &spro->dst, &sprn->dst);
	llsim_register_register("sp", "src0", 3, 0, &spro->src0, &sprn->src0);
	llsim_register_register("sp", "src1", 3, 0, &spro->src1, &sprn->src1);
	llsim_register_register("sp", "alu0", 32, 0, &spro->alu0, &sprn->alu0);
	llsim_register_register("sp", "alu1", 32, 0, &spro->alu1, &sprn->alu1);
	llsim_register_register("sp", "aluout", 32, 0, &spro->aluout, &sprn->aluout);
	llsim_register_register("sp", "immediate", 32, 0, &spro->immediate, &sprn->immediate);
	llsim_register_register("sp", "cycle_counter", 32, 0, &spro->cycle_counter, &sprn->cycle_counter);
	llsim_register_register("sp", "ctl_state", 3, 0, &spro->ctl_state, &sprn->ctl_state);
}

void sp_init(char *program_name)
{
	llsim_unit_t *llsim_sp_unit;
	llsim_unit_registers_t *llsim_ur;
	sp_t *sp;

	llsim_printf("initializing sp unit\n");

	inst_trace_fp = fopen("inst_trace.txt", "w");
	if (inst_trace_fp == NULL) {
		printf("couldn't open file inst_trace.txt\n");
		exit(1);
	}

	cycle_trace_fp = fopen("cycle_trace.txt", "w");
	if (cycle_trace_fp == NULL) {
		printf("couldn't open file cycle_trace.txt\n");
		exit(1);
	}

	llsim_sp_unit = llsim_register_unit("sp", sp_run);
	llsim_ur = llsim_allocate_registers(llsim_sp_unit, "sp_registers", sizeof(sp_registers_t));
	sp = llsim_malloc(sizeof(sp_t));
	llsim_sp_unit->private = sp;
	sp->spro = llsim_ur->old;
	sp->sprn = llsim_ur->new;

	sp->sram = llsim_allocate_memory(llsim_sp_unit, "sram", 32, SP_SRAM_HEIGHT, 0);
	sp_generate_sram_memory_image(sp, program_name);

	sp->start = 1;

	sp_register_all_registers(sp);
}
